/*!	 widget_vector.cpp
**	 Template File
**
**	Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
**
**	This package is free software; you can redistribute it and/or
**	modify it under the terms of the GNU General Public License as
**	published by the Free Software Foundation; either version 2 of
**	the License, or (at your option) any later version.
**
**	This package is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
**	General Public License for more details.
**
*/

#ifdef USING_PCH
#	include "pch.h"
#else
#ifdef HAVE_CONFIG_H
#	include <config.h>
#endif

#include <synfig/general.h>

#include <gtkmm/spinbutton.h>
#include "widgets/widget_vector.h"
#include "widgets/widget_distance.h"
#include "app.h"

#include <gui/localization.h>

#endif

using namespace std;
using namespace synfig;
using namespace studio;

#define DIGITS		10

Widget_Vector::Widget_Vector():
    Gtk::HBox(false, 5),
    x_adjustment(Gtk::Adjustment::create(0, -100000000, 100000000, 0.05, 0.05, 0)),
    y_adjustment(Gtk::Adjustment::create(0, -100000000, 100000000, 0.05, 0.05, 0))
{
    Gtk::Label *label;
    int width_chars = 5;

    label = manage(new class Gtk::Label("X:"));
    label->set_alignment(0, 0.5);

    entry_x = manage(new class Gtk::Entry());
    entry_x->set_width_chars(width_chars);
    entry_x->signal_changed().connect(sigc::mem_fun(*this, &studio::Widget_Vector::on_entry_x_changed));
    pack_start(*entry_x, Gtk::PACK_EXPAND_WIDGET);
    entry_x->show();

    spinbutton_x = manage(new class Gtk::SpinButton(x_adjustment, 0.05, DIGITS));
    spinbutton_x->set_alignment(1);
    spinbutton_x->set_update_policy(Gtk::UPDATE_ALWAYS);
    spinbutton_x->signal_value_changed().connect(sigc::mem_fun(*this, &studio::Widget_Vector::on_value_changed));
    pack_start(*spinbutton_x, Gtk::PACK_EXPAND_WIDGET);

    distance_x = manage(new Widget_Distance());
    distance_x->set_digits(4);
    distance_x->set_update_policy(Gtk::UPDATE_ALWAYS);
    distance_x->signal_value_changed().connect(sigc::mem_fun(*this, &studio::Widget_Vector::on_value_changed));
    pack_start(*distance_x, Gtk::PACK_EXPAND_WIDGET);

    label = manage(new class Gtk::Label("Y:"));
    label->set_alignment(0, 0.5);
    label->show();

    entry_y = manage(new class Gtk::Entry());
    entry_y->set_width_chars(width_chars);
    entry_y->signal_changed().connect(sigc::mem_fun(*this, &studio::Widget_Vector::on_entry_y_changed));
    pack_start(*entry_y, Gtk::PACK_EXPAND_WIDGET);
    entry_y->show();

    spinbutton_y = manage(new class Gtk::SpinButton(y_adjustment, 0.05, DIGITS));
    spinbutton_y->set_alignment(1);
    spinbutton_y->set_update_policy(Gtk::UPDATE_ALWAYS);
    spinbutton_y->signal_value_changed().connect(sigc::mem_fun(*this, &studio::Widget_Vector::on_value_changed));
    spinbutton_y->signal_activate().connect(sigc::mem_fun(*this, &studio::Widget_Vector::activate));
    pack_start(*spinbutton_y, Gtk::PACK_EXPAND_WIDGET);

    distance_y = manage(new Widget_Distance());
    distance_y->set_digits(4);
    distance_y->set_update_policy(Gtk::UPDATE_ALWAYS);
    distance_y->signal_value_changed().connect(sigc::mem_fun(*this, &studio::Widget_Vector::on_value_changed));
    pack_start(*distance_y, Gtk::PACK_EXPAND_WIDGET);


    entry_x->signal_activate().connect(sigc::mem_fun(*entry_y, &Gtk::SpinButton::grab_focus));
    entry_y->signal_activate().connect(sigc::mem_fun(*this, &studio::Widget_Vector::activate));
}

Widget_Vector::~Widget_Vector()
{
}

void
Widget_Vector::on_grab_focus()
{
    // else
    entry_x->grab_focus();
}

void
Widget_Vector::set_has_frame(bool x)
{
    if (spinbutton_x) {
        spinbutton_x->set_has_frame(x);
        spinbutton_y->set_has_frame(x);
        spinbutton_x->set_size_request(48, -1);
        spinbutton_y->set_size_request(48, -1);
    }

    distance_x->set_has_frame(x);
    distance_y->set_has_frame(x);
    distance_x->set_size_request(48, -1);
    distance_y->set_size_request(48, -1);

    entry_x->set_has_frame(x);
    entry_y->set_has_frame(x);
}

void
Widget_Vector::set_digits(int x)
{
    if (spinbutton_x) {
        spinbutton_x->set_digits(x);
        spinbutton_y->set_digits(x);
        spinbutton_x->set_size_request(48, -1);
        spinbutton_y->set_size_request(48, -1);
    }

    distance_x->set_digits(x);
    distance_y->set_digits(x);
    distance_x->set_size_request(48, -1);
    distance_y->set_size_request(48, -1);
}

void
Widget_Vector::set_value(const synfig::Vector &data)
{
    vector = data;

    if (canvas_) {
        try {
            Distance distx(vector[0], Distance::SYSTEM_UNITS), disty(vector[1], Distance::SYSTEM_UNITS);
            distx.convert(App::distance_system, canvas_->rend_desc());
            disty.convert(App::distance_system, canvas_->rend_desc());
            distance_x->set_value(distx);
            distance_y->set_value(disty);
            entry_x->set_text(distance_x->get_value().get_string(4));
            entry_y->set_text(distance_y->get_value().get_string(4));
        } catch (...) {
            synfig::error("Widget_Vector::set_value(): Caught something that was thrown");
        }
    } else {
        spinbutton_x->set_value(vector[0]);
        spinbutton_y->set_value(vector[1]);

        String str;
        std::ostringstream sstream_x;
        sstream_x << spinbutton_x->get_value();
        str = sstream_x.str();

        while (*str.rbegin() == '0' && str.length() > 1) {
            str = str.substr(0, str.size() - 1);
        }

        entry_x->set_text(str);
        std::ostringstream sstream_y;
        sstream_y << spinbutton_y->get_value();
        str = sstream_y.str();

        while (*str.rbegin() == '0' && str.length() > 1) {
            str = str.substr(0, str.size() - 1);
        }

        entry_y->set_text(str);

    }
}

const synfig::Vector &
Widget_Vector::get_value()
{
    if (!canvas_ && spinbutton_x) {
        vector[0] = spinbutton_x->get_value();
        vector[1] = spinbutton_y->get_value();
    } else try {
            vector[0] = distance_x->get_value().units(canvas_->rend_desc());
            vector[1] = distance_y->get_value().units(canvas_->rend_desc());
        } catch (...) {
            synfig::error("Widget_Vector::set_value(): Caught something that was thrown");
        }

    return vector;
}

void
Widget_Vector::on_entry_x_changed()
{
    if (canvas_) {
        Distance distx(0, Distance::SYSTEM_UNITS);
        distx.convert(App::distance_system, canvas_->rend_desc());
        distx = synfig::String(entry_x->get_text());
        distance_x->set_value(distx);
    } else try {
            spinbutton_x->set_value(atof(entry_x->get_text().c_str()));
        } catch (...) {
            synfig::error("Widget_Vector::set_value(): Caught something that was thrown");
        }
}

void
Widget_Vector::on_entry_y_changed()
{
    if (canvas_) {
        Distance disty(0, Distance::SYSTEM_UNITS);
        disty.convert(App::distance_system, canvas_->rend_desc());
        disty = synfig::String(entry_y->get_text());
        distance_y->set_value(disty);
    } else try {
            spinbutton_y->set_value(atof(entry_y->get_text().c_str()));
        } catch (...) {
            synfig::error("Widget_Vector::set_value(): Caught something that was thrown");
        }
}

void
Widget_Vector::on_value_changed()
{
    signal_value_changed()();
}

void
Widget_Vector::set_canvas(synfig::Canvas::LooseHandle x)
{
    canvas_ = x;

}

void
Widget_Vector::show_all_vfunc()
{

    entry_x->show();
    entry_y->show();
    show();
}